package lang

import (
	"JVM/Jvmgo/GoToJVM/native"
	"JVM/Jvmgo/GoToJVM/runtimeData"
	"JVM/Jvmgo/GoToJVM/runtimeData/heap"
)

func init() {
	native.Register("java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", arraycopy)
	native.Register("java/lang/System", "setIn0", "(Ljava/io/InputStream;)V", setIn0)
}

/*
参数：
	Object src
	int srcPos
	Object dest
	int destPos
	int length
*/

func arraycopy(frame *runtimeData.Frame) {
	// 获取本地方法表存储的5个参数
	vars := frame.LocalVars()
	src := vars.GetRef(0)
	srcPos := vars.GetInt(1)
	dest := vars.GetRef(2)
	destPos := vars.GetInt(3)
	length := vars.GetInt(4)

	if src == nil || dest == nil {
		panic("java.lang.NullPointerException")
	}
	// 检查两数组是否兼容，兼容才可进行arraycopy
	if !checkArrayCopy(src, dest) {
		panic("java.lang.ArrayStoreException")
	}
	// 检查srcPos，destPos，length参数
	if srcPos < 0 || destPos < 0 || length < 0 ||
		srcPos+length > src.ArrayLength() || destPos+length > dest.ArrayLength() {
		panic("java.lang.IndexOutOfBoundsException")
	}

	heap.ArrayCopy(src, dest, srcPos, destPos, length)
}

func checkArrayCopy(src, dest *heap.Object) bool {
	srcClass := src.Class()
	destClass := dest.Class()
	if !srcClass.IsArray() || !destClass.IsArray() {
		return false
	}
	if srcClass.ComponentClass().IsPrimitive() ||
		destClass.ComponentClass().IsPrimitive() {
		// 判断是否同种类型
		return srcClass == destClass
	}
	return true
}

// sout 支持方法
// private static native void setOut0 (PrintStream out)
func setIn0(frame *runtimeData.Frame) {
	out := frame.LocalVars().GetRef(0)
	sysClass := frame.Method().Class()
	sysClass.SetRefVar("out", "Ljava/io/PrintStream;", out)
}
